/**
 * 亿牛集团
 * 本源代码由亿牛集团及其作者共同所有，未经版权持有者的事先书面授权，
 * 不得使用、复制、修改、合并、发布、分发和/或销售本源代码的副本。
 *
 * @copyright Copyright (c) 2017 yiniu.com all rights reserved.
 */

package com.rico.simplejdbc.jdbc06.configs;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.querydsl.jpa.impl.JPAQueryFactory;
import org.apache.ibatis.session.SqlSessionFactory;
import org.hibernate.SessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.mybatis.spring.boot.autoconfigure.SpringBootVFS;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

/**
 * @author yaoyongfeng
 */
@Configuration
@EnableTransactionManagement() // 第五步 启注解事务管理，等同于xml配置方式的 <tx:annotation-driven />
@EnableJpaRepositories(//第四步:定义repository接口的存放目录,定义接口实现的后缀，通常用Impl,定义实体工厂的引用,定义事务管理器的引用
        basePackages = {"com.rico.simplejdbc.jdbc06.sdk",},
        repositoryImplementationPostfix = "Impl",
        entityManagerFactoryRef = "entityManagerFactorySdk",
        transactionManagerRef = "transactionManagerSdk"
)
@MapperScan(//mybatis配置
        basePackages = "com.rico.simplejdbc.jdbc06.sdk.mapper",
        sqlSessionFactoryRef = "sqlSessionFactorySdk",
        sqlSessionTemplateRef = "sqlSessionTemplateSdk")
public class DbSdkConfig {
    public static final String PERSISTENCE_UNIT_NAME = "persistenceUnitNameSdk";

    /*
     * 第一步
     * 配置数据库连接池Druid
     * */
    @Bean(initMethod = "init", destroyMethod = "close")
    @ConfigurationProperties("spring.datasource.druid.db-sdk")
    public DruidDataSource dbSdk() {
        return DruidDataSourceBuilder.create().build();
    }

    /*
     * 第二步
     * 定义实体的工厂bean
     * */
    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
    public LocalContainerEntityManagerFactoryBean entityManagerFactorySdk() {
        //参考 org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration.jpaVendorAdapter()
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setGenerateDdl(false);
        vendorAdapter.setShowSql(true);
//        vendorAdapter.setDatabase(org.springframework.orm.jpa.vendor.Database.MYSQL);
//        vendorAdapter.setGenerateDdl(env.getProperty("jpa.generateDdl",Boolean.class));
//        vendorAdapter.setShowSql(env.getProperty("jpa.showSql",Boolean.class));

        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setJpaVendorAdapter(vendorAdapter);
        factory.setPackagesToScan("com.rico.simplejdbc.jdbc06.sdk");//设置实体类所在位置
        factory.setDataSource(dbSdk());
        factory.setPersistenceUnitName(DbSdkConfig.PERSISTENCE_UNIT_NAME);

        return factory;
    }

    /*
     * 第三步
     * 定义事务管理器
     * */
    @Bean
    public PlatformTransactionManager transactionManagerSdk(@Qualifier("entityManagerFactorySdk") EntityManagerFactory entityManagerFactory) {
        JpaTransactionManager txManager = new JpaTransactionManager();
        txManager.setEntityManagerFactory(entityManagerFactory);
        return txManager;
    }

    //   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~hibernate session
    @Bean
    public SessionFactory sessionFactorySdk(@Qualifier("entityManagerFactorySdk") EntityManagerFactory entityManagerFactory) {
        if (entityManagerFactory.unwrap(SessionFactory.class) == null) {
            throw new NullPointerException("factory is not a hibernate factory");
        }
        return entityManagerFactory.unwrap(SessionFactory.class);
    }

    //    ～~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~使用mybatis配置
    @Bean
    public SqlSessionFactory sqlSessionFactorySdk(@Qualifier("dbSdk") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(dataSource);
        factory.setVfs(SpringBootVFS.class);
        factory.setVfs(SpringBootVFS.class);
        return factory.getObject();
    }

    @Bean
    public SqlSessionTemplate sqlSessionTemplateSdk(@Qualifier("sqlSessionFactorySdk") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

    //    ～~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~使用Query Dsl配置

    @Bean
    public JPAQueryFactory jpaQueryFactorySdk(@Qualifier("entityManagerFactorySdk") EntityManagerFactory entityManagerFactory) {
        JPAQueryFactory queryFactory = new JPAQueryFactory(entityManagerFactory.createEntityManager());
        return queryFactory;
    }

}
